<#

This script contains functions that enable a simple dependency-based 
loading mechanism for use at PowerShell Session startup.

#>

function Initialize-DependencyLoader {
	$global:MyLibraries = @{} <# $global:MyLibraries | ?? #> 
	Write-Host "DependencyLoader initialized"
}


<#

.SYNOPSIS

registers a Named Item with a set of InitDependencies and an InitAction

.DESCRIPTION

Register-Lib registers a Named Item with a set of InitDependencies and an InitAction

Calling Init-Lib on one of these items will recursively load all of its dependencies,
traversing the dependency tree and calling each Lib's InitAction in dependency order,
finally invoking the InitAction of the lib that we are actually initializing.
    
#>
function Register-Lib($Name, [ScriptBlock]$InitAction, $InitDependencies, [switch]$IsInitialized){
    if(!$global:MyLibraries[$Name]){
        $global:MyLibraries[$Name] = New-Object PSObject -Property @{
            Name = $Name;
            Dependencies = @($initDependencies);
            #InitializedDependencies = @();
            Action = $InitAction;
            IsInitialized=$IsInitialized
        }
    }
}

<#
.SYNOPSIS

Initializes the Named library, including all of its dependencies

.EXAMPLE

Initialize all libraries:

Init-Lib -AllLibs

.PARAMETER AllLibs

Ensures that all registered libraries are initialized

.NOTES

This script handles errors "gracefully", meaning it logs them and keeps going.

#>
function Init-Lib($Name, [switch] $AllLibs){
    $private:LibName = $Name
    if($allLibs){
        if($global:MyLibraries){
            @($global:MyLibraries.GetEnumerator()|%{$_}) `
                |lwpc -ActionLabel "initializing" -StatusReportBlock { $_.Name } `
                | % { $entry = $_
                    Init-Lib $entry.Name
                }
        }
    }
    else {        
        $private:entry = $global:MyLibraries[$libName]
        if(!$entry){
            Register-Lib $libName 
            Init-Lib $libName
        }
        if($entry -and (!($entry.IsInitialized))){
            
            # ensure dependencies
            $private:deps = $entry.Dependencies
            while($deps){
                $depName, $deps = $deps
                if($depName){
                    Init-Lib($depName)                                
                }
            }
            # run init handler
            Log-Verbose "Initializing $($entry.Name)"
            if($entry.Action){                
                try {
                    $private:action = [ScriptBlock]$entry.Action;
                    $_ = $entry
                    (& $action) | out-null
                } catch [Exception]{
                    Log "Error initializing $libName: $_"
                }
            }
            $entry.IsInitialized = $true
        }
    }
}

function TestInit-Libs {
    $global:InitOrder = @()
    $deps = @(
        ('E', ('A')),
        ('B', ('A')),
        ('C',('B')),
        ('D',('C')),
        ('A', (New-List))
    )
    $deps | % { 
    	Register-Lib -Name $_[0] -InitAction { 
            Log $_.Name; $global:InitOrder+=$_.Name 
        } -initDependencies:$_[1]
    }
    #Init-Lib -AllLibs
}
#TestInit-Libs

<#
function TestStartupAction {
    $a = 1
    RegisterStartupAction { Log "a is $a" }.GetNewClosure()
    $a = 2
    RegisterStartupAction { Log "a is $a" }.GetNewClosure()
    $a = 3
    RegisterStartupAction { Log "a is $a" }
    $a = 4
    RegisterStartupAction { Log "b is $b" }
    $c = 1
    RegisterStartupAction { Log "c is $c" }
    DoStartup
}
TestStartupAction
#>
